package com.nightpiter.view.dialogs;

import static com.nightpiter.controller.log.Logger.log;

import java.util.Map;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.nightpiter.R;
import com.nightpiter.controller.algorithms.MetroRouterState;
import com.nightpiter.controller.algorithms.Route;
import com.nightpiter.model.objects.Station;

/**
 * StationInfoDialog class.
 * 
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 */
public class RouteInfoDialog extends TransparentDialog implements
		OnClickListener {

	/**
	 * the subscriber that would be notified about most of events
	 */
	private Subscriber subscriber;

	/**
	 * station info
	 */
	private TextView nameText, openText, closeText;

	/**
	 * routes info
	 */
	private TextView routeCountText, routeTimeText, routeTransfersText,
			routeDestinationText;

	/**
	 * router buttons
	 */
	private Button routeNextButton, routePrevButton;

	/**
	 * common buttons
	 */
	private Button toggleButton, hideButton;

	/**
	 * the station, info of which is shown
	 */
	private Station currentStation;

	/**
	 * the currentRoute shown on the screen
	 */
	private Route currentRoute;

	/**
	 * all available routes
	 */
	private Route[] routes;

	/**
	 * number of current route displayed
	 */
	private int routesIterator = 0;

	/**
	 * the other end of the route
	 */
	private Station destinationStation;

	/**
	 * mode - router or stationInfo
	 */
	private boolean routerToggle = false;

	/**
	 * indicates the router state
	 */
	private boolean routerPrepared = false;

	/**
	 * this would be shown when routerToggle is off
	 */
	private LinearLayout stationInfoLayout;

	/**
	 * this would be shown when routerToggle is on
	 */
	private LinearLayout routerInfoLayout, routerCountLayout;

	// /**
	// * shows a progress of the router preparation
	// */
	// private ProgressDialog preparingProgress;

	/**
	 * @param context
	 */
	public RouteInfoDialog(Context context) {
		super(context);
	}

	/**
	 * @param context
	 * @param attrs
	 * @param inflateParams
	 */
	@SuppressWarnings("unchecked")
	public RouteInfoDialog(Context context, AttributeSet attrs,
			Map inflateParams) {
		super(context, attrs, inflateParams);
	}

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		init();
	}

	/**
	 * linking to layout views
	 */
	private void init() {
		this.nameText = (TextView) findViewById(R.id.text_station_name);
		this.openText = (TextView) findViewById(R.id.text_station_open);
		this.closeText = (TextView) findViewById(R.id.text_station_close);
		this.routeCountText = (TextView) findViewById(R.id.text_router_count);
		this.routeDestinationText = (TextView) findViewById(R.id.text_router_destination);
		this.routeTimeText = (TextView) findViewById(R.id.text_router_time);
		this.routeTransfersText = (TextView) findViewById(R.id.text_router_transfers);

		this.hideButton = (Button) findViewById(R.id.button_hide);
		this.toggleButton = (Button) findViewById(R.id.button_toggle);
		this.routeNextButton = (Button) findViewById(R.id.button_router_next);
		this.routePrevButton = (Button) findViewById(R.id.button_router_prev);

		this.stationInfoLayout = (LinearLayout) findViewById(R.id.layout_station_info);
		this.routerInfoLayout = (LinearLayout) findViewById(R.id.layout_router_info);
		this.routerCountLayout = (LinearLayout) findViewById(R.id.layout_router_count);

		this.hideButton.setOnClickListener(this);
		this.toggleButton.setOnClickListener(this);
		this.routeNextButton.setOnClickListener(this);
		this.routePrevButton.setOnClickListener(this);

		// this.preparingProgress = new ProgressDialog(this.getContext());
		// this.preparingProgress.setIndeterminate(true);
		// this.preparingProgress.setTitle("Preparing the MetroRouter");
		// this.preparingProgress.setCancelable(false);

		updateView();

	}

	/**
	 * update the view
	 */
	private void updateView() {
		if (routerToggle) {
			updateRouteInfo();
		} else {
			updateStationInfo();
		}
	}

	private void updateStationInfo() {
		stationInfoLayout.setVisibility(VISIBLE);
		routerInfoLayout.setVisibility(INVISIBLE);
		routerCountLayout.setVisibility(GONE);
		this.toggleButton.setText("Search routes from this Station");

		if (currentStation != null) {
			nameText.setText(currentStation.getName());
			openText.setText(currentStation.getOpenTime().toString());
			closeText.setText(currentStation.getCloseTime().toString());
		}
		setTextFields("", "", "", "");
		setButtonsEnabled(false, false);
	}

	private void updateRouteInfo() {
		stationInfoLayout.setVisibility(INVISIBLE);
		routerInfoLayout.setVisibility(VISIBLE);
		routerCountLayout.setVisibility(VISIBLE);
		this.toggleButton.setText("Back");

		if (!routerPrepared) {
			log("router is not yet prepared");
			routeCountText.setText("preparing");
			routeDestinationText.setText("the router");
			setButtonsEnabled(false, false);

		} else if (destinationStation == null) {
			log("router prepared, but destination is not selected");
			setTextFields("", "", "please select", "a destination");
			setButtonsEnabled(false, false);

		} else if (routes == null) {
			log("destination selected, but routes are not yet retrieved");
			setTextFields("", "", "searching", destinationStation.getName());
			setButtonsEnabled(false, false);

		} else if (routes.length == 0) {
			log("there are no routes to the destination");
			setTextFields("", "", "no routes to", destinationStation.getName());
			setButtonsEnabled(false, false);

		} else if (currentRoute == null) {
			// o_0
			log("WTF? seriously!");

		} else {
			log("regular view of router dialog");
			setTextFields("Total Time: " + currentRoute.getTotalDistance()
					+ " sec", "Transfers: " + currentRoute.getTransferHops()
					+ " hops", "there are " + routes.length + " routes to",
					destinationStation.getName());
			setButtonsEnabled(true, true);

		}

	}

	private void setTextFields(String timeText, String transferText,
			String countText, String destinationText) {
		routeTimeText.setText(timeText);
		routeTransfersText.setText(transferText);
		routeCountText.setText(countText);
		routeDestinationText.setText(destinationText);
	}

	private void setButtonsEnabled(boolean prevEnabled, boolean nextEnabled) {
		routePrevButton.setEnabled(prevEnabled);
		routeNextButton.setEnabled(nextEnabled);
	}

	/**
	 * a new station retrieved, process it
	 * 
	 * @param station
	 */
	public void processStation(Station station) {
		if (station == null) {
			hide();
			return;
		}
		if (!routerToggle) {
			currentStation = station;
			this.subscriber.onStationSelect(currentStation);
		} else {
			destinationStation = station;
			currentRoute = null;
			routes = null;
			routesIterator = 0;
			this.subscriber.onRouteSelect(null);
			this.subscriber.onRouteToDefine(station);
		}
		super.show();
		updateView();
	}

	/**
	 * an array of routes retrieved, display info
	 * 
	 * @param routes
	 */
	public void processRoutes(Route[] routes) {
		this.routes = routes;
		if (routes != null) {
			if (routes.length > 0) {
				routesIterator = 0;
				currentRoute = routes[0];
				this.subscriber.onRouteSelect(currentRoute);
			} else {
				Toast
						.makeText(getContext(), "No ways found",
								Toast.LENGTH_LONG);
			}
		} else {
			log("ERROR! null routes array retrieved");
		}
		updateView();
	}

	public void onRouterStateChanged(MetroRouterState state) {
		if (state.getAction() != MetroRouterState.Action.IDLE) {
			routerPrepared = false;
			routes = null;
			// preparingProgress.setMessage("Searching routes with "
			// + state.getPass() + " transfer hops");
			// preparingProgress.show();
			routeTimeText.setText("Searching routes");
			routeTransfersText.setText("with " + state.getPass()
					+ " transfer hops");
		} else if (state.isReady()) {
			routerPrepared = true;
			destinationStation = null;
			// if (preparingProgress.getWindow() != null) {
			// preparingProgress.dismiss();
			// }
			Toast.makeText(getContext(), "Please select a destination",
					Toast.LENGTH_LONG);
		}
		updateView();
	}

	public void onClick(View targetView) {
		if (targetView == this.hideButton) {
			hide();

		} else if (targetView == this.toggleButton) {
			routerToggle = !routerToggle;
			if (subscriber != null) {
				if (routerToggle) {
					routerPrepared = false;
					routesIterator = 0;
					routes = null;
					this.subscriber.onRouteFromDefine(currentStation);
				} else {
					this.subscriber.onRouteSelect(null);
				}
			}
			updateView();

		} else if (targetView == this.routeNextButton) {
			if (routesIterator < routes.length - 1) {
				currentRoute = routes[routesIterator++];
			}
			updateView();
			this.subscriber.onRouteSelect(currentRoute);

		} else if (targetView == this.routePrevButton) {
			if (routesIterator > 0) {
				currentRoute = routes[routesIterator--];
			}
			updateView();
			this.subscriber.onRouteSelect(currentRoute);

		}

	}

	@Override
	public void show() {
		super.show();
		if (subscriber != null) {
			this.subscriber.onStationSelect(currentStation);
			this.subscriber.onRouteSelect(currentRoute);
		}
	}

	@Override
	public void hide() {
		super.hide();
		currentStation = null;
		currentRoute = null;
		routes = null;
		routesIterator = 0;
		destinationStation = null;
		routerToggle = false;
		if (subscriber != null) {
			this.subscriber.onStationSelect(null);
			this.subscriber.onRouteSelect(null);
			this.subscriber.onDialogHide();
		}
	}

	/**
	 * subscribes to notifications
	 * 
	 * @param subscriber
	 *            the Subscriber
	 */
	public void subscribe(Subscriber subscriber) {
		if (subscriber != null) {
			this.subscriber = subscriber;
		}
	}

	/**
	 * Subscriber interface. Should be implemented by any class that would
	 * receive notifications from this View
	 * 
	 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
	 */
	public interface Subscriber {

		public void onRouteToDefine(Station toStation);

		public void onRouteFromDefine(Station fromStation);

		public void onRouteSelect(Route route);

		public void onStationSelect(Station station);

		public void onDialogHide();

	}

}
